package com.iflytek.aiui.demo.chat.repository.config;

import android.arch.lifecycle.LiveData;
import android.arch.lifecycle.MutableLiveData;
import android.content.Context;
import android.content.SharedPreferences;
import android.preference.PreferenceManager;
import android.text.TextUtils;

import com.iflytek.aiui.AIUIConstant;
import com.iflytek.aiui.AIUISetting;
import com.iflytek.aiui.demo.chat.BuildConfig;
import com.iflytek.aiui.demo.chat.common.Constant;
import com.iflytek.aiui.demo.chat.repository.Storage;

import org.json.JSONException;
import org.json.JSONObject;

import java.io.File;
import java.util.Iterator;

import javax.inject.Inject;
import javax.inject.Singleton;

@Singleton
public class AIUIConfigCenter {

    private static final String SDCARD_CONFIG_DIR = "/sdcard/AIUI/cfg";
    private static final String SDCARD_CONFIG_PATH = SDCARD_CONFIG_DIR + "/aiui.cfg";
    private static final String ASSETS_CONFIG_PATH = "cfg/aiui_phone.cfg";

    private Context mContext;
    private SharedPreferences mDefaultSharePreference;
    private JSONObject mAIUIConfig;
    private MutableLiveData<AIUIConfig> mLiveAIUIConfig = new MutableLiveData<>();
    private MutableLiveData<Boolean> mLiveWakeUpAvailable = new MutableLiveData<>();
    private MutableLiveData<Boolean> mLiveWakeUpEnable = new MutableLiveData<>();
    private MutableLiveData<Boolean> mLiveTransEnable = new MutableLiveData<>();
    private MutableLiveData<Boolean> mLiveTTSEnable = new MutableLiveData<>();

    private Settings mSetting;
    private Storage mStorage;
    private final String mDefaultAppid;
    private final String mDefaultAppKey;
    private final String mDefaultScene;

    @Inject
    public AIUIConfigCenter(Context context, Storage storage) {
        mContext = context;
        mStorage = storage;
        mDefaultSharePreference = PreferenceManager.getDefaultSharedPreferences(mContext);

        mAIUIConfig = retrieveAIUIConfig();
        mDefaultAppid = mAIUIConfig.optJSONObject("login").optString(Constant.KEY_APPID);
        mDefaultAppKey = mAIUIConfig.optJSONObject("login").optString(Constant.KEY_APP_KEY);
        mDefaultScene = mAIUIConfig.optJSONObject("global").optString(Constant.KEY_SCENE);

        updateConfigIfNeed();
    }

    public LiveData<AIUIConfig> getConfig() {
       return mLiveAIUIConfig;
    }

    public LiveData<Boolean> isWakeUpAvailable() {
        return mLiveWakeUpAvailable;
    }

    public LiveData<Boolean> isWakeUpEnable() {
        return mLiveWakeUpEnable;
    }

    public LiveData<Boolean> isTransEnable() {
        return mLiveTransEnable;
    }

    public LiveData<Boolean> isTTSEnable() {
        return mLiveTTSEnable;
    }

    public void updateConfigIfNeed()  {
        Settings settings = retrieveCurrentSettings();

        if(settings == mSetting) return;

        mSetting = settings;
        //设置后可在/sdcard/msc/下生成aiui.log日志
        if(mSetting.saveAIUILog){
            AIUISetting.setNetLogLevel(AIUISetting.LogLevel.info);
        }else {
            AIUISetting.setNetLogLevel(AIUISetting.LogLevel.none);
        }

        mLiveWakeUpEnable.postValue(mSetting.wakeup);
        mLiveTransEnable.postValue(mSetting.translation);
        mLiveTTSEnable.postValue(mSetting.tts);
        try {
            mAIUIConfig.optJSONObject("login").put("appid", settings.appid);
            mAIUIConfig.optJSONObject("login").put("key", settings.key);
            mAIUIConfig.optJSONObject("global").put("scene", settings.scene);
            mAIUIConfig.optJSONObject("log").put("debug_log", settings.debugLog?"1":"0");
            mAIUIConfig.optJSONObject("log").put("save_datalog", settings.saveDebugLog?"1":"0");
            if(settings.wakeup){
                //唤醒配置
                mAIUIConfig.optJSONObject("speech").put("wakeup_mode", "ivw");
                mAIUIConfig.optJSONObject("vad").put(AIUIConstant.KEY_VAD_EOS, String.valueOf(settings.eos));

                if(!mAIUIConfig.has("ivw")) {
                    JSONObject ivw = new JSONObject();
                    ivw.put("res_path", "ivw/ivw.jet");
                    ivw.put("res_type", "assets");
                    ivw.put("ivw_threshold", "0:2000");
                    mAIUIConfig.put("ivw", ivw);
                }
            } else {
                mAIUIConfig.optJSONObject("speech").put("wakeup_mode", "off");
                mAIUIConfig.optJSONObject("vad").put("vad_eos", "60000");
            }

            mAIUIConfig.optJSONObject("tts").put("play_mode", settings.tts ? "sdk" : "user");
            mLiveAIUIConfig.postValue(new AIUIConfig(mAIUIConfig, settings));
        } catch (JSONException e) {
            e.printStackTrace();
        }
    }

    public void config(String appid, String key, String scene) {
        //设置新的appid，key及scene，更新到sharePreference中
        SharedPreferences.Editor editor = mDefaultSharePreference.edit();
        editor.putString(Constant.KEY_APPID, appid);
        editor.putString(Constant.KEY_APP_KEY, key);
        editor.putString(Constant.KEY_SCENE, scene);
        editor.commit();

        updateConfigIfNeed();
    }

    public void mergeConfig(JSONObject config) {
        merge(config, mAIUIConfig);
    }

    private JSONObject retrieveAIUIConfig() {
        String config = mStorage.readSDFile(SDCARD_CONFIG_PATH);
        if(config == null) {
            //从assets下读取默认配置文件，写入到SD卡下
            config = mStorage.readAssetFile(ASSETS_CONFIG_PATH);
            assert config != null;
            new File(SDCARD_CONFIG_DIR).mkdirs();
            mStorage.writeSDFile(SDCARD_CONFIG_PATH, config.getBytes());
        }
        try {
            return new JSONObject(config);
        } catch (JSONException e) {
            e.printStackTrace();
            return null;
        }
    }

    public Settings retrieveCurrentSettings() {
        Settings settings = retrieveSettings();

        //将appid和key为空时恢复默认appid，key
        if(TextUtils.isEmpty(settings.appid) && TextUtils.isEmpty(settings.key)) {
            restoreDefaultConfig();
            settings = retrieveSettings();
        }

        //因为唤醒资源和appid绑定，当前appid不为默认配置时禁止唤醒功能开启
        if(!mDefaultAppid.equals(settings.appid)) {
            SharedPreferences.Editor editor = mDefaultSharePreference.edit();
            editor.putBoolean(Constant.KEY_AIUI_WAKEUP, false);
            editor.commit();
            mLiveWakeUpAvailable.postValue(false);
        } else {
            mLiveWakeUpAvailable.postValue(BuildConfig.WAKEUP_ENABLE);
        }

        settings = retrieveSettings();
        return settings;
    }

    private Settings retrieveSettings() {
        Settings settings = new Settings();
        settings.wakeup = mDefaultSharePreference.getBoolean(Constant.KEY_AIUI_WAKEUP, false);
        settings.translation = mDefaultSharePreference.getBoolean(Constant.KEY_AIUI_TRANSLATION, false);
        settings.translationScene = mDefaultSharePreference.getString(Constant.KEY_TRANS_SCENE, "trans");
        settings.bos = Integer.valueOf(mDefaultSharePreference.getString("aiui_bos", "5000"));
        settings.eos = Integer.valueOf(mDefaultSharePreference.getString("aiui_eos", "1000"));
        settings.debugLog = mDefaultSharePreference.getBoolean("aiui_debug_log", true);
        settings.saveDebugLog = mDefaultSharePreference.getBoolean("aiui_save_datalog", false);
        settings.appid = mDefaultSharePreference.getString(Constant.KEY_APPID, "");
        settings.key = mDefaultSharePreference.getString(Constant.KEY_APP_KEY, "");
        settings.scene = mDefaultSharePreference.getString(Constant.KEY_SCENE, "");
        settings.tts = mDefaultSharePreference.getBoolean(Constant.KEY_AIUI_TTS, true);
        settings.saveAIUILog = mDefaultSharePreference.getBoolean(Constant.KEY_AIUI_LOG, false);
        settings.accent = mDefaultSharePreference.getString(Constant.KEY_ACCENT, "mandarin");
        return settings;
    }


    /**
     * 恢复appid,key到默认配置
     */
    private void restoreDefaultConfig() {
        SharedPreferences.Editor editor = mDefaultSharePreference.edit();
        editor.putString(Constant.KEY_APPID, mDefaultAppid);
        editor.putString(Constant.KEY_APP_KEY, mDefaultAppKey);
        editor.putString(Constant.KEY_SCENE, mDefaultScene);
        editor.commit();
    }

    private void merge(JSONObject from, JSONObject to) {
        try {
            Iterator<String> keys = from.keys();
            Object obj1, obj2;
            while (keys.hasNext()) {
                String next = keys.next();
                if (from.isNull(next)) continue;
                obj1 = from.get(next);
                if (!to.has(next)) to.putOpt(next, obj1);
                obj2 = to.get(next);
                if (obj1 instanceof JSONObject && obj2 instanceof JSONObject) {
                    merge((JSONObject) obj1, (JSONObject) obj2);
                } else {
                    to.putOpt(next, obj1);
                }
            }
        } catch (JSONException e) {
            e.printStackTrace();
        }
    }
}

